package com.qf.commons.mysql.plugin;

import com.qf.commons.mysql.utils.MybatisUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Statement;

/**
 * description: SQL监控记录插件
 * author: Ken
 * 公众号：Java架构栈
 */
@Intercepts({
        @Signature(
                type = StatementHandler.class,//指定拦截器增强的内置对象的类型
                method = "query",//指定增强的内置对象中的方法
                args = {Statement.class, ResultHandler.class}//指定方法中的形参列表
        ),
        @Signature(
                type = StatementHandler.class,//指定拦截器增强的内置对象的类型
                method = "update",//指定增强的内置对象中的方法
                args = {Statement.class}//指定方法中的形参列表
        )
})
@Slf4j
public class SQLPlugin implements Interceptor {

    /**
     * 核心的拦截方法 ？？ 拦截哪个内置对象中的哪个方法
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        //记录当前执行的sql语句 & 记录sql语句执行的耗时
        StatementHandler statementHandler = (StatementHandler) MybatisUtils.getNoProxyObject(invocation.getTarget());//获取拦截的目标对象
        System.out.println("当前的statementHandler对象：" + statementHandler.getClass().getSimpleName());
        String sql = statementHandler.getBoundSql().getSql().toLowerCase().replaceAll("\n", "");//获取sql语句

        //记录执行的sql
        log.debug("[SQL - EXEC] 执行的sql语句：{}", sql);

        //记录sql的执行耗时
        long begin = System.currentTimeMillis();
        //执行SQL - 放行
        Object result = invocation.proceed();
        long end = System.currentTimeMillis();
        //计算耗时
        log.debug("[SQL - EXEC] sql的耗时：{}s", BigDecimal.valueOf(end).subtract(BigDecimal.valueOf(begin)).divide(BigDecimal.valueOf(1000)).setScale(6, RoundingMode.DOWN));

        //注意：放行后的结果一定要继续返回
        return result;
    }
}
